using System;
using System.IO;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.Network;

namespace OracleInternal.NotificationServices
{
	internal class Connection
	{
		internal enum Status
		{
			Idle,
			Connecting,
			Connected,
			Shutdown
		}

		private ONS ons;

		private NodeList nodeList;

		private int listIndex;

		private int concurrencyIndex;

		private string host;

		private int port;

		private string id;

		private object socketlock;

		private int waiters;

		private int serverVersion;

		protected static string RequestPrefix = "POST /connect HTTP/1.1\r\nContent-Length: 0\r\nOPMNtype: pm\r\nOPMNrequest: /";

		protected static string RequestFormFactor = "\r\nFormFactor: ";

		protected static string RequestSuffix = "\r\n\r\n";

		protected static string ResponseOK = "HTTP/1.1 200 OK";

		internal ONSTcpClient socket;

		internal ReceiverThread receiver;

		internal SenderThread sender;

		internal long scanDelay;

		internal bool shutdown;

		protected internal virtual int ConcurrencyIndex
		{
			get
			{
				return concurrencyIndex;
			}
			set
			{
				concurrencyIndex = value;
			}
		}

		protected internal virtual long ScanDelay
		{
			set
			{
				scanDelay = value;
			}
		}

		public virtual string Id => id;

		public virtual int ServerVersion
		{
			get
			{
				return serverVersion;
			}
			set
			{
				serverVersion = value;
			}
		}

		protected internal virtual int ListIndex => listIndex;

		protected internal virtual ReceiverThread ClientReceiver
		{
			set
			{
				receiver = value;
			}
		}

		protected internal virtual SenderThread ClientSender
		{
			set
			{
				sender = value;
			}
		}

		protected internal virtual bool ClientShutdown
		{
			set
			{
				lock (socketlock)
				{
					shutdown = value;
					if (value && waiters > 0)
					{
						Monitor.PulseAll(socketlock);
					}
				}
			}
		}

		internal Connection(NodeList cList, string cHost, int cPort, int index)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097408, OracleTraceClassName.Connection, OracleTraceFuncName.ctor);
			}
			nodeList = cList;
			ons = cList.ons;
			host = cHost;
			port = cPort;
			listIndex = index;
			socketlock = new object();
			socket = null;
			scanDelay = 0L;
			shutdown = false;
			waiters = 0;
			id = nodeList.getId() + "-" + host + ":" + port;
			serverVersion = 4;
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097664, OracleTraceClassName.Connection, OracleTraceFuncName.ctor);
			}
		}

		protected internal virtual ONSTcpClient getClientSocket(bool block)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097408, OracleTraceClassName.Connection, OracleTraceFuncName.getClientSocket);
			}
			ONSTcpClient result = null;
			lock (socketlock)
			{
				waiters++;
				while (!shutdown && block && socket == null)
				{
					try
					{
						Monitor.Wait(socketlock);
					}
					catch (Exception ex)
					{
						OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)270532608, OracleTraceClassName.Connection, OracleTraceFuncName.getClientSocket, ex);
					}
				}
				waiters--;
				result = socket;
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097664, OracleTraceClassName.Connection, OracleTraceFuncName.getClientSocket);
			}
			return result;
		}

		protected internal virtual void setClientSocket(ONSTcpClient sock)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097408, OracleTraceClassName.Connection, OracleTraceFuncName.setClientSocket);
			}
			if (socket != null)
			{
				try
				{
					socket.Close();
				}
				catch (IOException ex)
				{
					OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)270532608, OracleTraceClassName.Connection, OracleTraceFuncName.setClientSocket, ex);
				}
				socket = null;
			}
			lock (socketlock)
			{
				socket = sock;
				if (waiters > 0)
				{
					Monitor.PulseAll(socketlock);
				}
			}
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097664, OracleTraceClassName.Connection, OracleTraceFuncName.setClientSocket);
			}
		}

		protected internal virtual void closeClientSocket()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097408, OracleTraceClassName.Connection, OracleTraceFuncName.closeClientSocket);
			}
			try
			{
				ONSTcpClient oNSTcpClient;
				lock (socketlock)
				{
					oNSTcpClient = socket;
					socket = null;
				}
				oNSTcpClient?.Close();
				serverVersion = 4;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)270532608, OracleTraceClassName.Connection, OracleTraceFuncName.closeClientSocket, ex);
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097664, OracleTraceClassName.Connection, OracleTraceFuncName.closeClientSocket);
				}
			}
		}

		protected internal virtual ONSTcpClient connect()
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097408, OracleTraceClassName.Connection, OracleTraceFuncName.connect);
			}
			ONSTcpClient result = null;
			SqlNetOraConfig sNOConfig = new SqlNetOraConfig();
			try
			{
				string Dir = null;
				bool flag = false;
				if ((!string.IsNullOrEmpty(ConfigBaseClass.m_ONSProtocol) && string.Compare(ConfigBaseClass.m_ONSProtocol, "TCPS", StringComparison.InvariantCultureIgnoreCase) == 0) || !string.IsNullOrEmpty(ConfigBaseClass.m_ONSWalletLocation))
				{
					flag = true;
					if (!string.IsNullOrEmpty(ConfigBaseClass.m_ONSWalletLocation))
					{
						Dir = ConfigBaseClass.GetResolvedFileLocation(ConfigBaseClass.m_ONSWalletLocation);
						Dir = SqlNetOraConfig.HandlePathSeparators(Dir);
					}
					else
					{
						SqlNetOraConfig.GetWalletLoc(null, sNOConfig, out Dir, out var HT);
						if (!string.IsNullOrEmpty(Dir))
						{
							string text = "FILE";
						}
						else if (HT != null)
						{
							string text = ((string)HT["METHOD"]).ToUpperInvariant();
							if (text != null && text == "FILE")
							{
								Dir = (string)HT["DIRECTORY"];
							}
						}
						if (!string.IsNullOrEmpty(Dir))
						{
							Dir = ConfigBaseClass.GetResolvedFileLocation(Dir);
							Dir = SqlNetOraConfig.HandlePathSeparators(Dir);
						}
					}
					if (ProviderConfig.m_bTraceLevelPrivate)
					{
						Trace.Write(OracleTraceLevel.Private, OracleTraceTag.ONS, OracleTraceClassName.Connection, OracleTraceFuncName.connect, "MY_WALLET_DIRECTORY = " + Dir);
					}
					if (string.IsNullOrEmpty(Dir))
					{
						throw new NetworkException(-6400);
					}
				}
				string str = "tcp://";
				if (flag)
				{
					str = "tcps://";
				}
				str = str + host + ":" + port;
				if (flag)
				{
					str = str + "?ssl_server_dn_match=off&wallet_location=" + Dir;
				}
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, OracleTraceTag.ONS, OracleTraceClassName.Connection, OracleTraceFuncName.connect, "EZConnect used for ONS Connection = " + str);
				}
				OracleCommunication oracleCommunication = new OracleCommunication(new ConOraBufPool(new OraBufPool(5)));
				oracleCommunication.RAW = true;
				oracleCommunication.Connect(str, null);
				result = new ONSTcpClient(oracleCommunication.Socket, oracleCommunication.SocketStream);
				return result;
			}
			catch (Exception ex)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)270532608, OracleTraceClassName.Connection, OracleTraceFuncName.connect, ex);
				return result;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)2097664, OracleTraceClassName.Connection, OracleTraceFuncName.connect);
				}
			}
		}

		private static bool ValidateRemoteCertificate(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors policyErrors)
		{
			return true;
		}
	}
}
